package upm.pb4agent.team3;

import jade.content.lang.Codec;
import jade.content.lang.Codec.CodecException;
import jade.content.lang.sl.SLCodec;
import jade.content.onto.Ontology;
import jade.content.onto.OntologyException;
import jade.content.onto.basic.Action;
import jade.core.AID;
import jade.core.Agent;
import jade.core.behaviours.SimpleBehaviour;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.wrapper.AgentContainer;
import jade.wrapper.AgentController;

import java.util.Date;

import upm.pb4agent.ontology.Dock;
import upm.pb4agent.ontology.DockDesignation;
import upm.pb4agent.ontology.PB4AgentOntology;
import upm.pb4agent.ontology.Registration;
import upm.pb4agent.ontology.RegistrationForm;
import upm.pb4agent.ontology.TeamID;



/**
 * This agent has the following functionality: 
 * <ul>
 * <li> TeamManager register Rower in the DF
 * <li> TeamManager decides where is the dock where Rower board the boat.
 * <li> Waits for being allowed to board the boat
 * <li> 
 *      
 * </ul>
 * @author Team3, UPM
 * @version $Date: 2012/04/17 11:23:35 $ $Revision: 1.1 $
 **/
public class Manager extends Agent {	
	private static final long serialVersionUID = 3570392251197898901L;
		
	private Codec codec = new SLCodec();
    private Ontology ontology = PB4AgentOntology.getInstance();
												
	private AID agRegistrationDeskAid = null; 
	
	private AID[] agRowersAidArrays = new AID[Constant.MAX_NUMBER_OF_ROWERS];
    private Registration registration = new Registration();
    
    long registrationPeriodProp = 0;
    long TIME_4_SEARCH_AG_REGISTRATION = 0;
    long TIME_4_REGISTRATION_RESPONSE = 0;
    
    protected void setup(){
  		System.out.println(getLocalName() + ": enters the system");
  		
        getContentManager().registerLanguage(codec);
        getContentManager().registerOntology(ontology);

        MyAgent.registerAgentInDF(this,Constant.SD_MANAGER);               
        
        createRowersAgents();
        
        //create the team
	    setRegistrationForm();
	    
	    
	    ReadConfiguration.getInstance(0);
		String registrationPeriodStr = ReadConfiguration.getValue("registration_period");		
		registrationPeriodProp = Long.valueOf(registrationPeriodStr);
		TIME_4_SEARCH_AG_REGISTRATION = registrationPeriodProp/4;
		TIME_4_REGISTRATION_RESPONSE = 3*registrationPeriodProp;
		
  		
  		//BEHAVIOURS ****************************************************************  		
		addBehaviour(new RegisterRowersToRegistrationDesk(this));
		addBehaviour(new ProcessResponseRegisterRowersFromRegistrationDesk(this));
		
  		//addBehaviour(new SubscriptionInitiatorToReferee(this));
  	}
    
    
	// Adds a behavior to search a RegistrationDesk agent
	// IF it is found, send a  Request to register 4 rowers
	// ELSE, keep trying to Register the team        
	//Ini: addBehaviour(new SimpleBehaviour(this){
	//From this moment, it will registring 4 rowers in a loop		
    class RegisterRowersToRegistrationDesk extends SimpleBehaviour {
		private static final long serialVersionUID = 1325653803627308096L;
		boolean end = false;
		final Date registerTime = new Date();
		
		public RegisterRowersToRegistrationDesk(Agent agent) {			
			super(agent);
			myAgent = agent;			
		}
		//Ini: action
		public void action(){ 
			try{	  				  					 
				agRegistrationDeskAid = MyAgent.searchAgentInDF(super.myAgent,Constant.SD_REGISTRATION_DESK);
				if(agRegistrationDeskAid != null){
					//Ini: proceso de registro
					// Request the register to the registration agent
					ACLMessage msg = new ACLMessage(ACLMessage.REQUEST);
					msg.addReceiver(agRegistrationDeskAid);
					msg.setLanguage(codec.getName());
					msg.setOntology(ontology.getName());								  						
					msg.setProtocol("Registration");  						
					
					Action agAction = new Action(agRegistrationDeskAid,registration);

					getContentManager().fillContent(msg, agAction);
					send(msg);  						  					
					
					//System.out.println(getLocalName() +": send a 'REQUEST' -> " + Constant.REGISTRATION_PIC);					
  					//Fin: proceso de registro
					end = true;
				}else{
					doWait(TIME_4_SEARCH_AG_REGISTRATION);//(Constant.TIME_4_SEARCH_AG_REGISTRATION);
				}
				
				//If has been searching for estimations for more than a minute, it does not search any more
				if ((new Date()).getTime() - registerTime.getTime() >= TIME_4_REGISTRATION_RESPONSE){//Constant.TIME_4_REGISTRATION_RESPONSE
					end = true;
					System.out.println(myAgent.getLocalName() + ": time for register is over, and " + Constant.TEAM_ID + " wasn't registered.");
				}
			
			}catch (CodecException ce){
				System.out.println(Constant.NAME_MANAGER + ", error: "+ ce.toString());
				end = true;
			}catch (OntologyException oe){
				System.out.println(Constant.NAME_MANAGER + ", error: "+ oe.toString());
				end = true;
			}catch (Exception e) {
				System.out.println(Constant.NAME_MANAGER + ", error: "+ e.toString());
				end = true;
			}
	    }
		//End: action
					
        public boolean done(){
        	return end;
        }
	}
    
    class ProcessResponseRegisterRowersFromRegistrationDesk extends SimpleBehaviour {
    	private static final long serialVersionUID = 4168006178103786229L;
    	final Date responseTime = new Date();		
		boolean end = false; 
		
		public ProcessResponseRegisterRowersFromRegistrationDesk(Agent agent) {			
			super(agent);
			myAgent = agent;			
		}
		
		//Ini: action
		public void action(){
			// Waits for the arrival of an answer
			ACLMessage msg = receive(MessageTemplate.MatchPerformative(ACLMessage.INFORM));
			
			if(msg == null){
				if ((new Date()).getTime() - responseTime.getTime() >= TIME_4_REGISTRATION_RESPONSE){//Constant.TIME_4_REGISTRATION_RESPONSE
					System.out.println(myAgent.getLocalName() + " -::- time over and no response has been recived");
					end = true;
				}else{// If no message has yet arrived, the behavior blocks itself
					block();
					end = false;
				}
			}else{//if(msg != null){				
				end = true;					
				if(msg.getPerformative() == ACLMessage.INFORM) {
					//System.out.println(myAgent.getLocalName() + " <-- " + " team was registered with success");					
				}else if(msg.getPerformative() == ACLMessage.REFUSE) {
					
				}else if(msg.getPerformative() == ACLMessage.NOT_UNDERSTOOD) {
					try{
						//2nd form to register, group 4
  						ACLMessage msg2 = new ACLMessage(ACLMessage.REQUEST);
  						msg2.addReceiver(agRegistrationDeskAid);
  						msg2.setLanguage(codec.getName());
  						msg2.setOntology(ontology.getName());								  						
  						msg2.setProtocol("Registration");  	
  						Action agAction2 = new Action(agRegistrationDeskAid,registration.getRegistrationForm());

  						getContentManager().fillContent(msg, agAction2);
  						send(msg2);
  						//2nd form to register
					}catch(Exception e){
						
					}
				}else{
					
				}
			}
		}
		//End: action
			
		public boolean done(){
			return end;
		}
    }
    
    
    
	public boolean createRowersAgents() {	
		try{
			AgentContainer agentContainer = getContainerController();
			
			AgentController agentController = agentContainer.createNewAgent(   Constant.NAME_ROWER_1
																			 , Constant.CLASS_ROWER
													 		  				 , new String[] { Constant.NAME_DOCK_A, "1" });
			agentController.start();				

			agentController = agentContainer.createNewAgent(   Constant.NAME_ROWER_2
															 , Constant.CLASS_ROWER
	  				 										 , new String[] { Constant.NAME_DOCK_B, "2" });
			agentController.start();

			agentController = agentContainer.createNewAgent(   Constant.NAME_ROWER_3
															 , Constant.CLASS_ROWER
						 									 , new String[] { Constant.NAME_DOCK_C, "3" });
			agentController.start();

			agentController = agentContainer.createNewAgent(   Constant.NAME_ROWER_4
															 , Constant.CLASS_ROWER
					 										 , new String[] { Constant.NAME_DOCK_D, "4" });
			agentController.start();
			
			agRowersAidArrays[0] = new AID( Constant.NAME_ROWER_1, AID.ISLOCALNAME);
			agRowersAidArrays[1] = new AID( Constant.NAME_ROWER_2, AID.ISLOCALNAME);
			agRowersAidArrays[2] = new AID( Constant.NAME_ROWER_3, AID.ISLOCALNAME);
			agRowersAidArrays[3] = new AID( Constant.NAME_ROWER_4, AID.ISLOCALNAME);
			
			return true;
		}catch(Exception e){
			System.out.println(Constant.NAME_MANAGER + ", error: " + e.toString());
			return false;
		}
	}

	
	private RegistrationForm setRegistrationForm(){
		try{
			RegistrationForm registrationForm = new RegistrationForm();			
			TeamID teamID = new TeamID();
			teamID.setValue(Constant.TEAM_ID);
			registrationForm.setTeamID(teamID);			  							
			
			DockDesignation dockDesignationA = new DockDesignation();
			Dock dockA = new Dock(); 
			dockA.setName(Constant.NAME_DOCK_A);
			dockDesignationA.setDock(dockA);  								
			dockDesignationA.setRowerID(agRowersAidArrays[0]);
			
			DockDesignation dockDesignationB = new DockDesignation();					
			Dock dockB = new Dock();
			dockB.setName(Constant.NAME_DOCK_B);
			dockDesignationB.setDock(dockB);
			dockDesignationB.setRowerID(agRowersAidArrays[1]);
			
			DockDesignation dockDesignationC = new DockDesignation();
			Dock dockC = new Dock();
			dockC.setName(Constant.NAME_DOCK_C);
			dockDesignationC.setDock(dockC);
			dockDesignationC.setRowerID(agRowersAidArrays[2]);
			
			DockDesignation dockDesignationD = new DockDesignation();
			Dock dockD = new Dock(); 
			dockD.setName(Constant.NAME_DOCK_D);
			dockDesignationD.setDock(dockD);
			dockDesignationD.setRowerID(agRowersAidArrays[3]);
			
			registrationForm.addDockDesignation(dockDesignationA);
			registrationForm.addDockDesignation(dockDesignationB);
			registrationForm.addDockDesignation(dockDesignationC);
			registrationForm.addDockDesignation(dockDesignationD);
			
			registration.setRegistrationForm(registrationForm);
			
			return registrationForm;
		}catch(Exception e){
			System.out.println(Constant.NAME_MANAGER + ", error: "+ e.toString());
			return null;
		}
	}
}